package ui;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.InputVerifier;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;

import entity.EntityConstants;
import entity.RecurrenceRule;

/**
 * A Panel that contains options to generate and modify 
 * recurrence rules with the "monthly" frequency.
 * 
 * @author Sean Young
 * @version 1.0
 *
 */
public class MonthlyPanel extends JPanel implements EntityConstants, ActionListener{
	private JPanel intervalPanel, buttonPanel, endPanel, neverPanel, afterCountPanel, onDatePanel;
	private JComboBox intervalBox;
	private JSpinner count;
	private JRadioButton never, afterCount, onDate;
	private JTextField endDate;
	private DateVerifier dateVerifier;
	private JLabel validationLabel;
	private CreateEventPanel parent;
	
	/**
	 * Constructor for the MonthlyPanel. Requires a reference
	 * to the main panel of the CalendarUI.
	 * @param parent The main panel
	 */
	public MonthlyPanel(CreateEventPanel parent) {
		super();
		setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
		setPreferredSize(new Dimension(270, 100));
		this.parent = parent;
		
		intervalPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
		intervalPanel.add(new JLabel("Repeat Every "));
		
		Integer[] intervalOptions = new Integer[30];
		for(int i = 0; i < 30; i++) {
			intervalOptions[i] =  i + 1;
		}
		
		intervalBox = new JComboBox<Integer>(intervalOptions);
		intervalPanel.add(intervalBox);
		intervalPanel.add(new JLabel("months"));
		add(intervalPanel);
		
		add(Box.createVerticalGlue());
		
		endPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
		endPanel.add(new JLabel("Ends "));
		add(endPanel);
		
		
		buttonPanel = new JPanel();
		buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.PAGE_AXIS));
		
		never = new JRadioButton();
		never.setActionCommand("never");
		never.addActionListener(this);
		afterCount = new JRadioButton();
		afterCount.setActionCommand("afterCount");
		afterCount.addActionListener(this);
		onDate = new JRadioButton();
		onDate.setActionCommand("onDate");
		onDate.addActionListener(this);
		
		never.setSelected(true);
		
		ButtonGroup endButtons = new ButtonGroup();
		endButtons.add(never);
		endButtons.add(afterCount);
		endButtons.add(onDate);
		
		neverPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
		neverPanel.add(never);
		neverPanel.add(new JLabel("Never"));
		neverPanel.setPreferredSize(new Dimension(200,25));
		
		afterCountPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
		afterCountPanel.add(afterCount);
		afterCountPanel.add(new JLabel("After"));
		SpinnerModel model = new SpinnerNumberModel(1, 1, 1000, 1);
		count = new JSpinner(model);
		count.setEnabled(false);
		afterCountPanel.add(count);
		afterCountPanel.add(new JLabel("occurrences"));
		afterCountPanel.setPreferredSize(new Dimension(210,25));
		
		onDatePanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
		onDatePanel.add(onDate);
		onDatePanel.add(new JLabel("On "));
		onDatePanel.setPreferredSize(new Dimension(210,25));
		
		DateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");
		Calendar currentDate = Calendar.getInstance();
		currentDate.add(Calendar.MONTH, 1);
		
		dateVerifier = new DateVerifier();
		
		endDate = new JTextField(dateFormat.format(currentDate.getTime()), 10);
		endDate.setInputVerifier(dateVerifier);
		endDate.addActionListener(dateVerifier);
		endDate.setEnabled(false);
		
		validationLabel = new JLabel("   ");
		validationLabel.setForeground(Color.RED);
		onDatePanel.add(endDate);
		onDatePanel.add(validationLabel);
		
		buttonPanel.add(neverPanel);
		buttonPanel.add(afterCountPanel);
		buttonPanel.add(onDatePanel);
		
		endPanel.add(buttonPanel);
	}
	
	/**
	 * Generates a RRULE with the specified properties.
	 * @return A recurrence rule with a monthly frequency
	 */
	public RecurrenceRule buildRRule() {
		RecurrenceRule rrule = new RecurrenceRule();
		rrule.addFrequency(FREQUENCY_MONTHLY);
		
		if(intervalBox.getSelectedIndex() != 0){
			rrule.addInterval((int)intervalBox.getSelectedItem());
		}
		
		if(afterCount.isSelected()) {
			rrule.addCount((int) count.getValue());
		} else if(onDate.isSelected()) {
			Date d = toDate(endDate.getText());
			if(d != null) {
				rrule.addUntil(d);
			}
		}
		
		return rrule;
	}
	
	/**
	 * Converts the properly formatted string into
	 * a Date object.
	 * @param s The properly formatted date string
	 * @return The date
	 */
	public Date toDate(String s) {
		if(s == null) return null;
		SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
		sdf.setLenient(false);
		
		try {
			Date validDate = sdf.parse(s);
			return validDate;
		} catch (ParseException e) {
			return null;
		}
	}
	
	public void actionPerformed(ActionEvent e) {
		switch(e.getActionCommand()) {
			case "never":	   count.setEnabled(false);
							   endDate.setEnabled(false);
							   break;
			case "afterCount": count.setEnabled(true);
							   endDate.setEnabled(false);
							   break;
			case "onDate":     count.setEnabled(false);
							   endDate.setEnabled(true);
							   break;
		}
	}
	
	/**
	 * Verifies the user input in the end date field.
	 */
	public class DateVerifier extends InputVerifier implements ActionListener {
		
		/**
		 * Verifies the validity of the end date field by checking
		 * the following conditions.
		 */
		@Override
		public boolean verify(JComponent comp) {
			if(!(isValidDateFormat(endDate.getText()))) {
				validationLabel.setText("Incorrect  Date Format. Required Format(MM/DD/YYYY)");
				return false;
			} 
				
			if(parent.hasValidStartDate()) {
				if(parent.getStartDate().after(toDate(endDate.getText()))) {
					validationLabel.setText("The Start Date must be before the End Date.");
					return false;
				}
				if(parent.getStartDate().equals(toDate(endDate.getText()))) {
					validationLabel.setText("The Start Date cannot be equal to the End Date.");
					return false;
				}
			}
			
			return true;
		}
		
		/**
		 * Returns whether the given string is a properly formatted
		 * Date
		 * @param date The string to be checked
		 * @return The validity of the string
		 */
		public boolean isValidDateFormat(String date) {
			if(date == null) return false;
			SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
			sdf.setLenient(false);
			
			try {
				Date validDate = sdf.parse(date);
				return true;
			} catch (ParseException e) {
				return false;
			}
		}
		
		/**
		 * Returns whether the component should yield focus
		 * to other components. It will always evaluate to
		 * true to allow user to manipulate other fields
		 */
		public boolean shouldYieldFocus(JComponent comp) {
			boolean inputOK = verify(comp);
			if(inputOK) {
				validationLabel.setText("   ");
				((JTextField) comp).setBackground(Color.WHITE);
				return true;
			} else {
				((JTextField) comp).setBackground(Color.PINK);
				return true;
			}
		}
		
		/**
		 * Performs the validation operations upon detecting
		 * an ActionEvent.
		 */
		public void actionPerformed(ActionEvent e) {
			JTextField source = (JTextField) e.getSource();
			shouldYieldFocus(source);
			source.selectAll();
		}
	}
}

